#include <hidef.h> /* for EnableInterrupts macro */
#include "Headers/derivative.h" /* include peripheral declarations */
#include "Headers/time.h"
#include "Headers/dvr_i2cVirtual.h"



void vfnStart(void);
void vfnStop(void);
unsigned char cfni2c_ACK(void);
void vfni2c_NACK(void);
void vfni2c_Send_ACK(void);
void vfnTransmit_byte(unsigned char dtt);
unsigned char cfnReceive_byte(void);
int ifnSelective_read(unsigned char addres, unsigned char Waddr, unsigned char Numdata, char *lpub_DataPointer);
int ifnWrite_byte(unsigned char addres, unsigned char Waddr, unsigned char Numdata, char *datos);
int ifnByteOnly_read(unsigned char addres, unsigned char Waddr, char *lpub_DataPointer);


int ifnByteOnly_read(unsigned char addres, unsigned char Waddr, char *lpub_DataPointer){
	volatile unsigned char lub_error = 0;			//variable de manejo de error
	unsigned char lub_auxAddr = 0;
	unsigned char lub_CountAux=0;
	
	
	vfnStart();									//Start condition
	vfnTransmit_byte(addres);					//Salve Address, write operation 
	lub_error = cfni2c_ACK();					//Wait for ACK
	if(lub_error >0){
		vfnStop();	
	 	return 0x01;
	} 
	vfnTransmit_byte(Waddr);					//Word Addres
	lub_error = cfni2c_ACK();					//wait ACK
	if(lub_error >0){
		vfnStop();	
	 	return 0x02;
	} 
	vfnStart();									//Start condition
	lub_auxAddr = addres | 0x01;				//Change address to write mode.
	vfnTransmit_byte(lub_auxAddr);				//Salve Address, read operation
	lub_error = cfni2c_ACK();					//Wait for ACK
	if(lub_error >0){
		vfnStop();	
	 	return 0x01;
	} 
	lub_CountAux = cfnReceive_byte();
	//*lpub_newByte = cfnReceive_byte();		//wait for data
	*lpub_DataPointer = lub_CountAux;		//wait for data
	vfni2c_NACK();								//Send NAK
	vfnStop();									//Stop condition
	
	return 0;
}

/*********************************************************************************
 *  Nombre               : 	ifnWrite_byte
 *  Descripcion          : 	funcion que graba un byte 
 *  Parametros           : 	addres: direccion del esclavo
 * 							Waddr: 	direccion de la palabra
 * 							dato:	Byte a guardar.
 *  Retorno              : 	numero de error:
 * 							0x01: Error en direccion, No responde el Dispositivo 
 * 							0x02: Error en WADDR, No recivio el word address
 * 							0x03: Error en Dato, no recivio bien el dato
 *  Critical/explanation : 	ninguna
 ********************************************************************************/

int ifnWrite_byte(unsigned char addres, unsigned char Waddr, unsigned char Numdata, char *datos){
	unsigned char lub_error = 0;			//variable de manejo de error
	unsigned char lub_cntaux = 0;			//variable de control de numero de datos
	
	vfnStart();									//Start condition 
	vfnTransmit_byte(addres);					//Salve Addres
	lub_error = cfni2c_ACK();					//Wait for ACK
	if(lub_error >0){
		 vfnStop();		//if NACK return
		 return 0x01;
	}
	vfnTransmit_byte(Waddr);					//Word Addres
	lub_error = cfni2c_ACK();					//ACK
	if(lub_error >0){
		 vfnStop();		//if NACK return
		 return 0x02;
	}
	lub_cntaux = Numdata;
	do{
		vfnTransmit_byte(datos[Numdata-lub_cntaux]);						//Byte to write 
		lub_error = cfni2c_ACK();					//ACK
		if(lub_error >0){
		 	vfnStop();	//if NACK return
		 	return 0x03;
		}
		lub_cntaux--;
	}while(lub_cntaux);
	vfnStop();									//Stop condition.
	
	return 0;
}


/*********************************************************************************
 *  Nombre               : 	ifnSelective_read
 *  Descripcion          : 	Funcion de lectura secuencial 
 *  Parametros           : 	addres: direccion del esclavo
 * 							Waddr: 	direccion de la palabra inicial.
 * 							Numdata: numero de Bytes a guardar.
 * 							lpub_DataPointer: puntero donde guardar la informacion 
 *  Retorno              : 	numero de error:
 * 							0x01: Error en direccion, No responde el Dispositivo 
 * 							0x02: Error en WADDR, No recivio el word address
 * 							0x03: Error en Dato, no recivio bien el dato
 *  Critical/explanation : 	ninguna
 ********************************************************************************/

int ifnSelective_read(unsigned char addres, unsigned char Waddr, unsigned char Numdata, char *lpub_DataPointer){
	volatile unsigned char lub_error = 0;			//variable de manejo de error
	//char *lpub_newByte = 0;  // hugo comento esta linea por que me generaba un error en el micro
	unsigned char lub_auxAddr = 0;
	unsigned char lub_CountAux=0 ;//i = 0;// hugo comento esta linea por que me generaba un error en el micro
	
//	lpub_newByte = malloc(Numdata +1);
	//for(i=0; i<Numdata +1; i++) lpub_newByte[i] = 0;// hugo comento esta linea por que me generaba un error en el micro
	
	vfnStart();									//Start condition
	vfnTransmit_byte(addres);					//Salve Address, write operation 
	lub_error = cfni2c_ACK();					//Wait for ACK
	if(lub_error >0){
		vfnStop();	
	 	return 0x01;
	} 
	vfnTransmit_byte(Waddr);					//Word Addres
	lub_error = cfni2c_ACK();					//wait ACK
	if(lub_error >0){
		vfnStop();	
	 	return 0x02;
	} 
	vfnStart();									//Start condition
	lub_auxAddr = addres | 0x01;				//Change address to write mode.
	vfnTransmit_byte(lub_auxAddr);				//Salve Address, read operation
	lub_error = cfni2c_ACK();					//Wait for ACK
	if(lub_error >0){
		vfnStop();	
	 	return 0x01;
	} 
	lub_CountAux = Numdata;
	do{
		lpub_DataPointer[Numdata-lub_CountAux] = cfnReceive_byte();		//wait for data
		lub_CountAux--;
		if(lub_CountAux != 0){vfni2c_Send_ACK();}//Send ACK
	}while(lub_CountAux);
	vfni2c_NACK();								//Send NAK
	vfnStop();									//Stop condition
	//memcpy(lpub_DataPointer,lpub_newByte,Numdata);//Copy the data to de pointer
	//for(i = 0; i<Numdata; i++){
	//	lpub_DataPointer[i] = lpub_newByte[i]; // en el caso del for lo comente y cambie en la parte de recepcion directamente al puntero que esta como parametro en esta funcion
	//}
	
//	free(lpub_newByte);
	return 0;
}


/*********************************************************************************
 *  Nombre               : 	cfnReceive_byte
 *  Descripcion          : 	Lee un byte de los puertos del i2c.
 *  Parametros           :  ninguno
 *  Retorno              : 	ninguno
 *  Critical/explanation : 	ninguna
 ********************************************************************************/
 
unsigned char cfnReceive_byte(void){
	unsigned char lub_aux = 0;			//contador auxiliar
	unsigned char luw_bit = 0;			//guarda el bit del valor del SDA
	unsigned char lub_temp = 0;			//guarda el byte recivido
	
	SDA_mode(INPUT);							//como entrada SDA
	SCL_mode(OUTPUT);							//como salida SCL
	delay1;
	
	lub_aux = 8;
	do{
		SCL(1);
		delay1;
		luw_bit = INVALUE(SDA_shift);			// lee dato en puerto 
		lub_temp <<= 1;							// Recorre un bit a la izq
		lub_temp |= luw_bit;					// OR con el bit adquirido 
		SCL(0);
		delay1;
		lub_aux--;
	}while(lub_aux);
	return lub_temp;
}
/*********************************************************************************
 *  Nombre               : 	vfnTransmit_byte
 *  Descripcion          : 	Transmite un byte a los puertos del i2c.
 *  Parametros           :  ddt: Es el dato que se quiere transmitir por el bus.
 *  Retorno              : 	ninguno
 *  Critical/explanation : 	ninguna
 ********************************************************************************/
 
void vfnTransmit_byte(unsigned char dtt){
	unsigned char lub_aux = 0;			//contador auxiliar
	unsigned char lub_dttAux = 0;			//auxiliar del dato 
	
	lub_aux = 8;
	lub_dttAux = dtt;
	do{
		if((lub_dttAux & 0x80) == 0x80){
			 SDA(1);
		}else SDA(0);
		lub_dttAux <<= 1;
//		delay1;
		SCL(1);
		delay1;
		SCL(0);
		delay_us(3); // hugo puso este delay de 3 microsegundos 
		lub_aux--;
	}while(lub_aux);
}

/*********************************************************************************
 *  Nombre               : 	vfnStart
 *  Descripcion          : 	Funcion para realizar la condicion Start en i2c
 *  Parametros           :  ninguno 
 *  Retorno              : 	ninguno
 *  Critical/explanation : 	ninguna
 ********************************************************************************/
void vfnStart(void){
	SDA(1);
	SCL(1);
	SDA_mode(OUTPUT);
	SCL_mode(OUTPUT);			
	delay1;
	delay1;
	SDA(0);
	SCL(1);
	delay1;
	SDA(0);
	SCL(0);
	delay1;
}

/*********************************************************************************
 *  Nombre               : 	vfnStop
 *  Descripcion          : 	Funcion para realizar la condicion Stop en i2c
 *  Parametros           :  ninguno 
 *  Retorno              : 	ninguno
 *  Critical/explanation : 	ninguna
 ********************************************************************************/
void vfnStop(void){
	SDA(0);
	SCL(0);
	delay1;
	SDA(0);
	SCL(1);
	delay1;
	SDA(1);
	SCL(1);
	delay1;
	SDA_mode(INPUT);							//como entrada SDA
	SCL_mode(INPUT);							//como salida SCL
}

/*********************************************************************************
 *  Nombre               : 	cfni2c_ACK
 *  Descripcion          : 	Funcion para recivir un ACK en el bus I2C
 *  Parametros           :  ninguno 
 *  Retorno              : 	Num error.
 *  Critical/explanation : 	ninguna
 ********************************************************************************/
unsigned char cfni2c_ACK(void){
	unsigned int luw_SDAvalue = 0;		// variable para lectura del puerto SDA
	unsigned char lub_rtvalue = 0;
	SDA_mode(INPUT);							//como entrada SDA
	SCL_mode(OUTPUT);							//como salida SCL
//	delay1;
	SCL(1);
	delay1;
	luw_SDAvalue = INVALUE(SDA_shift);		// funcion de adquisicion
	if(luw_SDAvalue == 1) {
		lub_rtvalue = 1;
	}else{
		lub_rtvalue = 0;
	}
	SCL(0);
	delay1;
	
	SDA_mode(OUTPUT);							//como salida SDA
	delay1;
	return lub_rtvalue;
}

/*********************************************************************************
 *  Nombre               : 	vfni2c_NACK
 *  Descripcion          : 	Funcion para enviar un no ACK
 *  Parametros           :  ninguno 
 *  Retorno              : 	ninguno
 *  Critical/explanation : 	ninguna
 ********************************************************************************/
void vfni2c_NACK(void){
	SDA_mode(OUTPUT);							//como entrada SDA
	SCL_mode(OUTPUT);							//como salida SCL
	delay1;
	SCL(1);
	SDA(1);										//Pone SDA y SCL a 1
	delay1;
	SCL(0);
	SDA(0);										//Pone SDA y SCL a 0
	delay1;
}

/*********************************************************************************
 *  Nombre               : 	vfni2c_Send_ACK
 *  Descripcion          : 	Funcion para enviar un ACK
 *  Parametros           :  ninguno 
 *  Retorno              : 	ninguno
 *  Critical/explanation : 	ninguna
 ********************************************************************************/

void vfni2c_Send_ACK(void){
	SCL(0);
	SDA(0);					//Pone SDA a 0 y SCL a 0
	SDA_mode(OUTPUT);							//como entrada SDA
	SCL_mode(OUTPUT);							//como salida SCL 
	delay1;
	SCL(1);
	SDA(0);						//Pone SDA a 0 y SCL a 1
	delay1;
	SCL(0);
	SDA(0);						//Pone SDA y SCL a 0
}

